/*
 * 
 */
package carAgents;

import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.Behaviour;
import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.TickerBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

import java.util.ArrayList;
import java.util.List;

// TODO: Auto-generated Javadoc
/**
 * The Class RequestAgent.
 */
@SuppressWarnings("serial")
public class RequestAgent extends Agent {
	
	/** The my gui. */
	private RequestAgentGui myGui;
	
	/** The req. */
	private Request req;
	//list of know offerers
	/** The offering agents. */
	private AID[] offeringAgents;
	
	/** The is blocked. */
	private Boolean isBlocked=false;
	
	/** The offers. */
	private ArrayList<ACLMessage> offers = null;
	
	/** The which position. */
	private int whichPosition = -1;
	
	/** The is canceled. */
	private Boolean isCanceled = false;
	
	/** The info is purchased. */
	private String infoIsPurchased = "";
	
	/** The is refresh. */
	private Boolean isRefresh = false;
	
	/** The is bought. */
	private Boolean isBought = false;

	/* (non-Javadoc)
	 * @see jade.core.Agent#setup()
	 */
	protected void setup() {
		req = new Request();
		offers = new ArrayList<ACLMessage>();
		System.out.println("Welcome! Asking agent "+getAID().getLocalName()+" is waiting for an offer.");
		myGui = new RequestAgentGui (this);
		myGui.display();
		Tools.addNewRequest(getLocalName());
		//time interval for asking agent between sending cfp
		//input argment from command line
		int interval = 500;
		Object[] args = getArguments();
		if (args != null && args.length > 0) 
			interval = Integer.parseInt(args[0].toString());
		addBehaviour(new TickerBehaviour(this, interval)
		{
			protected void onTick()
			{
				//look for only if there is a starting point call
				if (!req.isEmpty() && !isBlocked)
				{
					offers.clear();
					isBlocked=true;
					infoIsPurchased = "";
					whichPosition = -1;
					System.out.println("I am looking for Journey " + req.toString2());
					//update a list of known offers
					DFAgentDescription template = new DFAgentDescription();
					ServiceDescription sd = new ServiceDescription();
					sd.setType("car-offer");
					template.addServices(sd);
					try
					{
						DFAgentDescription[] result = DFService.search(myAgent, template);
						System.out.println("Offer found:");
						offeringAgents = new AID[result.length];
						for (int i = 0; i < result.length; i++)
						{
							offeringAgents[i] = result[i].getName();
							System.out.println(offeringAgents[i].getLocalName());
						}
					}
					catch (FIPAException fe)
					{
						fe.printStackTrace();
					}

					myAgent.addBehaviour(new RequestPerformer());
				}
			}
		});
	}

	/**
	 * Gets the offers.
	 *
	 * @return the offers
	 */
	public ArrayList<ACLMessage> getOffers() {
		ArrayList<ACLMessage> offersClear = new ArrayList<ACLMessage>();
		List<String> unBlocked = new ArrayList<String>();
		List<String> all = new ArrayList<String>();
		for(int i=0;i<offers.size();i++){
			all.add(offers.get(i).getSender().getLocalName());
			System.out.println(offers.get(i).getSender().getLocalName());
		}
		unBlocked=Tools.checkBlockedList(all,this.getLocalName());
		System.out.println(this.getLocalName());
		for(int i=0;i<offers.size();i++){
			boolean unBlock=false;
			int unBlockIndex=0;
			for (int j=0;j<unBlocked.size();j++){
				if(offers.get(i).getSender().getLocalName().equals(unBlocked.get(j))){
					unBlock=true;
					unBlockIndex=i;
					break;
				}
			}
				if(unBlock==true){
					offersClear.add(offers.get(unBlockIndex));
				}
		}
		System.out.println("unb"+offersClear.size());
		return offersClear;
	}

	/**
	 * Gets the which position.
	 *
	 * @return the which position
	 */
	public int getWhichPosition() {
		return whichPosition;
	}

	/**
	 * Sets the which position.
	 *
	 * @param whichPosition the new which position
	 */
	public void setWhichPosition(int whichPosition) {
		this.whichPosition = whichPosition;
	}

	/**
	 * Gets the checks if is canceled.
	 *
	 * @return the checks if is canceled
	 */
	public Boolean getIsCanceled() {
		return isCanceled;
	}

	/**
	 * Sets the checks if is canceled.
	 *
	 * @param isCanceled the new checks if is canceled
	 */
	public void setIsCanceled(Boolean isCanceled) {
		this.isCanceled = isCanceled;
	}

	/**
	 * Gets the info is purchased.
	 *
	 * @return the info is purchased
	 */
	public String getInfoIsPurchased() {
		return infoIsPurchased;
	}

	/**
	 * Sets the info is purchased.
	 *
	 * @param infoIsPurchased the new info is purchased
	 */
	public void setInfoIsPurchased(String infoIsPurchased) {
		this.infoIsPurchased = infoIsPurchased;
	}

	/**
	 * Gets the checks if is refresh.
	 *
	 * @return the checks if is refresh
	 */
	public Boolean getIsRefresh() {
		return isRefresh;
	}

	/**
	 * Sets the checks if is refresh.
	 *
	 * @param isRefresh the new checks if is refresh
	 */
	public void setIsRefresh(Boolean isRefresh) {
		this.isRefresh = isRefresh;
	}

	/**
	 * Gets the checks if is bought.
	 *
	 * @return the checks if is bought
	 */
	public Boolean getIsBought() {
		return isBought;
	}

	//method call by gui for reqest
	/**
	 * Look for journey.
	 *
	 * @param f_req the f_req
	 */
	public void lookForJourney(final Request f_req)
	{
		addBehaviour(new OneShotBehaviour()
		{
			public void action()
			{
				req = f_req;
				System.out.println("The Journey is " + f_req.toString());
			}
		});
	}

	/* (non-Javadoc)
	 * @see jade.core.Agent#takeDown()
	 */
	protected void takeDown() {
		myGui.dispose();
		System.out.println("Requesting agent " + getAID().getName() + " is dead.");
	}

	/**
	 * The Class RequestPerformer.
	 */
	private class RequestPerformer extends Behaviour {

		/** The replies cnt. */
		private int repliesCnt = 0;
		
		/** The mt. */
		private MessageTemplate mt;
		
		/** The step. */
		private int step = 0;

		/* (non-Javadoc)
		 * @see jade.core.behaviours.Behaviour#action()
		 */
		public void action() {

			switch (step) {
			case 0:
				ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
				for (int i = 0; i < offeringAgents.length; ++i) {
					cfp.addReceiver(offeringAgents[i]);
				}
				cfp.setContent(req.toString());
				cfp.setConversationId("car-pool");
				cfp.setReplyWith("cfp"+System.currentTimeMillis()); //unique value
				myAgent.send(cfp);
				mt = MessageTemplate.and(MessageTemplate.MatchConversationId("car-pool"),
						MessageTemplate.MatchInReplyTo(cfp.getReplyWith()));
				step = 1;
				break;	
			case 1:
				ACLMessage reply = myAgent.receive(mt);
				if (reply != null) {
					if (reply.getPerformative() == ACLMessage.PROPOSE) {
						offers.add(reply);
					}
					repliesCnt++;
					if(repliesCnt >= offeringAgents.length) {
						step = 2;
					}
				}
				else {
					block();
				}
				break;
			case 2:
				//zakup najlepszej oferty
				if (whichPosition >= 0) {
					ACLMessage order = new ACLMessage(ACLMessage.ACCEPT_PROPOSAL);
					order.addReceiver(offers.get(whichPosition).getSender());
					order.setContent(req.toString());
					order.setConversationId("car-pool");
					order.setReplyWith("order"+System.currentTimeMillis());
					myAgent.send(order);
					mt = MessageTemplate.and(MessageTemplate.MatchConversationId("car-pool"),
							MessageTemplate.MatchInReplyTo(order.getReplyWith()));
					step = 3;
				}
				break;
			case 3:      
				//potwierdzenie zakupu przez agenta sprzedajacego
				reply = myAgent.receive(mt);
				if (reply != null) {
					if (reply.getPerformative() == ACLMessage.INFORM) {
						infoIsPurchased = "Journey "+req.toString2()+" with "+reply.getSender().getLocalName()+" was taken";
						System.out.println("Journey "+req.toString2()+" with "+reply.getSender().getLocalName()+" was taken");
						System.out.println("New Request.");
						isBought = true;
						req = new Request();
						//myAgent.doDelete();
					}
					else {
						req = new Request();
						infoIsPurchased = "Contract failed. This offer is already taken or revoked.";
						isBought = false;
						System.out.println("Contract failed. This offer is already taken or revoked.");
					}
					step = 4;	
				}
				else {
					block();
				}
				break;
			}        
		}

		/* (non-Javadoc)
		 * @see jade.core.behaviours.Behaviour#done()
		 */
		public boolean done() {
			if (step == 2 && offers.size() == 0) {
				//System.out.println(req+" unavalible");
			}

			//System.out.println("done");
			//System.out.println((step == 2 && offers.size() == 0) || step == 4);
			if ((step == 2 && offers.size() == 0) || step == 4) {
				isBlocked=false;
				return true;
			}
			if (isCanceled == true) {
				req = new Request();
				isCanceled = false;
				isBlocked = false;
				return true;
			}
			if (isRefresh == true) {
				offers.clear();
				isRefresh = false;
				step = 0; 
				repliesCnt = 0;
			}
			return false;
			//koniec jesli ksiazki nie ma w sprzedazy lub nie udalo sie kupic

			//return ((step == 2 && offer == null) || step == 4);
		}
	}

}
